﻿using System;
using System.Net;
using CommonFramework.Log;
using CommonFramework.Serialize.BytesArray;
using Delegate = CommonFramework.Event.Delegate;

namespace Net
{
    public static class NetUtil
    {
        /// <summary>
        /// Udp数据包的最大字节数
        /// </summary>
        public const int MAX_UDP_PACKET_SIZE = 1472;

        #region 数据包工具

        public static Delegate.Param1WithRet<string, object> PacketCreater;

        public static string GetPacketName<T>() where T : NetPacket
        {
            if (typeof(T) == typeof(NetPacket))
                return "";
            return typeof(T).FullName;
        }
        public static string GetPacketName(Type type)
        {
            if(!type.IsSubclassOf(typeof(NetPacket)))
                return "";
            return type.FullName;
        }

        /// <summary>
        /// 对消息包名进行编码
        /// </summary>
        public static void EncodePacketName(NetPacket packet,BytesWriter writer)
        {
            if (packet == null)
                return;
            string name = packet.PacketName;
            if (string.IsNullOrEmpty(name))
                return;

            writer.WriteString(name);
        }
        /// <summary>
        /// 对消息包名进行反编码,解析出消息包名.
        /// 如果字节长度不够,返回空串.out count表示成功读取的字节数
        /// </summary>
        public static string DecodePacketName(BytesReader reader)
        {
            if (reader.DataLength()<sizeof(int))
                return "";

            int len = reader.ReadInt32();
            if (len > reader.DataLength())
            {
                reader.RevertReadIndex(sizeof(int));
                return "";
            }
            else
            {
                reader.RevertReadIndex(sizeof(int));
                string name = reader.ReadString();
                return name;
            }
        }

        public static BytesBuffer GetBytesFromPacket(NetPacket packet)
        {
            BytesBuffer packetBuffer = new BytesBuffer();
            var writer= packetBuffer.GetWriter();
            //消息包名序列化
            writer.WriteString(packet.PacketName);
            //消息包体序列化
            packet.WriteToBytes(writer);

            BytesBuffer sendBuffer = new BytesBuffer();
            sendBuffer.GetWriter().WriteUInt16((ushort) packetBuffer.DataLength());
            sendBuffer.GetWriter().WriteBytes(packetBuffer.Bytes, packetBuffer.DataStart(), packetBuffer.DataLength());

            return sendBuffer;
        }
        public static bool TryGetPacketFromBytes(BytesBuffer recvBuffer, out NetPacket packet)
        {
            var reader = recvBuffer.GetReader();
            packet = null;
            if (reader.DataLength() < 2) //长度信息不够
                return false;
            //整个消息包的字节长度
            ushort totalLen = reader.ReadUInt16();
            if (recvBuffer.DataLength() < totalLen) //消息包不完整
            {
                reader.RevertReadIndex(sizeof(ushort));
                return false;
            }
            
            //解析消息包名
            int beforeReadIndex= reader.ReadIndex;
            string packetName = DecodePacketName(reader);
            if (string.IsNullOrEmpty(packetName))
            {
                LogUtil.LogError("parse message name failed");
                return false;
            }
            int nameLen = reader.ReadIndex - beforeReadIndex;

            //解析消息包体
            int bodyLen = totalLen - nameLen;
            Type innerType = Type.GetType(packetName);
            if (innerType != null)
            {
                packet=Activator.CreateInstance(innerType) as NetPacket;
            }
            else
            {
                packet = PacketCreater.Invoke(packetName) as NetPacket;
            }
            
            if (packet == null)
            {
                LogUtil.LogError($"create MsgBase failed,from msgName={packetName}");
                return false;
            }

            packet.ReadFromBytes(reader);
            reader.TryMoveDataToOrigin();
            return true;
        }

        #endregion

        //IpEndPoint转换工具
        public static IPEndPoint ToIpEndPoint(string host, int port)
        {
            if (string.IsNullOrEmpty(host) || port <= 0)
                return null;
            return new IPEndPoint(IPAddress.Parse(host), port);
        }
        public static IPEndPoint ToIpEndPoint(EndPoint ep)
        {
            if (ep == null)
                return null;
            string host = "";
            int port = 0;
            FromEndPoint(ep,ref host, ref port);
            return ToIpEndPoint(host, port);
        }
        public static void FromEndPoint(EndPoint ep, ref string host, ref int port)
        {
            if (ep != null)
            {
                string address = ep.ToString();
                int index = address.LastIndexOf(':');
                host = address.Substring(0, index);
                port = int.Parse(address.Substring(index + 1));
            }
        }
    }
}